#include "serialcharx.h"
#include  <qdebug>
#include <QDockWidget>
#include <QTextEdit>
#include <QMdiArea>
#include <QCloseEvent>
#include <QSettings>
#include <QTreeWidget>
#include <QTreeWidgetItem>
#include <QPushButton>
#include <QModelIndex>
#include <QMessageBox>
#include <QFileDialog>
#include <QFileInfo>
#include <QColorDialog>
#include <QPalette>
#include "qwt_plot_renderer.h"
#include <QtPrintSupport/QPrinter>
#include <QtPrintSupport/QPrintDialog>
#include "csvdecoder.h"

SerialCharX::SerialCharX(QWidget *parent)
	: QMainWindow(parent)
{	
	m_ser = NULL;
	m_curveDockWin = NULL;
	m_consoleDockWin = NULL;
	m_main_plot = NULL;
	m_decoder = new CsvDecoder();
	m_curDir = ".";
	connect(m_decoder, &CsvDecoder::recv_a_point, this, &SerialCharX::plotOnRecvPoint);

	setWindowIcon(QIcon(":/SerialCharX/Resources/images/app.ico"));
	ui.setupUi(this);
	setCurrentFile("");
	delete(ui.mainToolBar);
	createMainPlotWin();
	createActions();
	createMenus();
	createToolBars();
	createDockWin();

	// restore setting
	readSettings();

	// connect signal & slot, run
	connect(&m_main_loop_timer, &QTimer::timeout, this, &SerialCharX::mainLoop);
	m_main_loop_timer.start(100);
}

SerialCharX::~SerialCharX()
{
	// disconnect(&m_main_loop_timer, &QTimer::timeout, this, &SerialCharX::mainLoop);
	// stopPlot();
}

void SerialCharX::mainLoop(void)
{
}

void SerialCharX::newFile(void)
{
	setCurrentFile("");
}

void SerialCharX::openFile(void)
{
	QString fileName = QFileDialog::getOpenFileName(this,
		tr("Open SerialCharX"), m_curDir,
		tr("SerialCharX files (*.scx)"));

	if (!fileName.isEmpty())
	{
		loadFile(fileName);
		plotAutoScale();
		setCurrentFile(fileName);
	}
}

void SerialCharX::exportTo(void)
{
	QwtPlotRenderer renderer;
	renderer.exportTo(m_main_plot, "");
}

void SerialCharX::printTo(void)
{
	QPrinter printer(QPrinter::HighResolution);

	QString docName = m_main_plot->title().text();
	if (!docName.isEmpty())
	{
		docName.replace(QRegExp(QString::fromLatin1("\n")), tr(" -- "));
		printer.setDocName(docName);
	}

	printer.setCreator(APP_NAME);
	printer.setOrientation(QPrinter::Landscape);

	QPrintDialog dialog(&printer);
	if (dialog.exec())
	{
		QwtPlotRenderer renderer;

		if (printer.colorMode() == QPrinter::GrayScale)
		{
			renderer.setDiscardFlag(QwtPlotRenderer::DiscardBackground);
			renderer.setDiscardFlag(QwtPlotRenderer::DiscardCanvasBackground);
			renderer.setDiscardFlag(QwtPlotRenderer::DiscardCanvasFrame);
			renderer.setLayoutFlag(QwtPlotRenderer::FrameWithScales);
		}

		renderer.renderTo(m_main_plot, printer);
	}
}

void SerialCharX::save(void)
{
	if (m_curFile.isEmpty()) {
		return saveAs();
	}
	else {
		saveFile(m_curFile);
	}
}

void SerialCharX::saveAs(void)
{
	QString fileName = QFileDialog::getSaveFileName(this,
		tr("Save SerialCharX"), m_curDir,
		tr("SerialCharX files (*.scx)"));

	if (fileName.isEmpty())
		return;

	setCurrentFile(fileName);
	saveFile(fileName);
}

void SerialCharX::startPlot(void)
{
	stopPlot();

	m_ser = new SerialIo(m_ser_port_list->currentText(), m_ser_bdrate_list->currentText().toInt());
	if (!m_ser->_open())
	{
		QMessageBox::warning(this, tr("Open error"), QString::fromLatin1("Can not open ") + m_ser_port_list->currentText());
		delete m_ser;
		m_ser = NULL;
		return;
	}

	connect(m_ser, &SerialIo::DataReady, this, &SerialCharX::on_recv_io_data);
	connect(m_consoleDockWin, &ConsoleDockWin::send, m_ser, &SerialIo::_write);
}

void SerialCharX::stopPlot(void)
{
	if (m_ser)
	{
		disconnect(m_ser, &SerialIo::DataReady, this, &SerialCharX::on_recv_io_data);
		disconnect(m_consoleDockWin, &ConsoleDockWin::send, m_ser, &SerialIo::_write);
		m_ser->_close();
		delete m_ser;
		m_ser = NULL;
	}
}

void SerialCharX::plotSetup(void)
{

}

void SerialCharX::plotCanvasColorSet(void)
{
	QColor c = QColorDialog::getColor(m_main_plot->getCanvasColor());
	if (c.isValid())
	{
		m_main_plot->setCanvasColor(c);
		m_main_plot->replot();
	}
}

void SerialCharX::plotAutoScale(void)
{
	m_main_plot->setAxisAutoScale(QwtPlot::yLeft, true);
	m_main_plot->setAxisAutoScale(QwtPlot::xBottom, true);
	m_main_plot->replot();
}

void SerialCharX::plotDel(void)
{
	m_curveDockWin->delAllCurvePoint();
	m_curveDockWin->clearCurve();
	m_main_plot->replot();
}

void SerialCharX::plotMax(void)
{
	m_curveDockWinViewAction->setChecked(false);
	m_consoleDockWinViewAction->setChecked(false);
	m_curveDockWin->hide();
	m_consoleDockWin->hide();
}

void SerialCharX::plotMin(void)
{
	m_curveDockWinViewAction->setChecked(true);
	m_consoleDockWinViewAction->setChecked(true);
	m_curveDockWin->show();
	m_consoleDockWin->show();
}

void SerialCharX::curveDockWinViewOnOff(void)
{
	if (m_curveDockWinViewAction->isChecked())
	{
		m_curveDockWin->show();
	}
	else
	{
		m_curveDockWin->hide();
	}
}

void SerialCharX::consoleDockWinViewOnOff(void)
{
	if (m_consoleDockWinViewAction->isChecked())
	{
		m_consoleDockWin->show();
	}
	else
	{
		m_consoleDockWin->hide();
	}
}

void SerialCharX::setCurrentFile(const QString &fileName)
{
	QFileInfo fileinfo;

	m_curFile = fileName;
	fileinfo = QFileInfo(m_curFile);
	m_curDir = fileinfo.absolutePath();;
}

bool SerialCharX::loadFile(const QString &fileName)
{
	QFile file(fileName);
	if (!file.open(QIODevice::ReadOnly)) {
		QMessageBox::warning(this, tr("SerialCharX"),
			tr("Cannot read file %1:\n%2.")
			.arg(file.fileName())
			.arg(file.errorString()));
		return false;
	}

	m_curveDockWin->clearCurve();
	QDataStream in(&file);
	in.setVersion(QDataStream::Qt_5_9);
	QApplication::setOverrideCursor(Qt::WaitCursor);
	int curveCount;
	in >> curveCount;
	while (!in.atEnd()) {
		CurveItem *curve = new CurveItem("", Qt::white);
		in >> *curve;
		m_curveDockWin->addCurve(curve);
	}
	QApplication::restoreOverrideCursor();

	return true;
}

bool SerialCharX::saveFile(const QString &fileName)
{
	QFile file(fileName);
	if (!file.open(QIODevice::WriteOnly)) 
	{
		QMessageBox::warning(this, tr("SerialCharX"),
			tr("Cannot write file %1:\n%2.")
			.arg(file.fileName())
			.arg(file.errorString()));
		return false;
	}

	QApplication::setOverrideCursor(Qt::WaitCursor);
	QDataStream out(&file);
	out.setVersion(QDataStream::Qt_5_9);
	out << m_curveDockWin->curveCount();
	QList<CurveItem *> curveList = m_curveDockWin->getCurveList();
	for (auto curve : curveList)
	{
		out << *curve;
	}
	QApplication::restoreOverrideCursor();

	return true;
}

void SerialCharX::plotOnRecvPoint(PointData point)
{
	m_calc_time.start();
	CurveItem *curve;
	curve = m_curveDockWin->findCurveByName(point.m_tag);
	if (NULL == curve)
	{
		qDebug() << "un-using color:" << m_curveDockWin->findUnsedCurveColor();
		curve = new CurveItem(point.m_tag, m_curveDockWin->findUnsedCurveColor());
		m_curveDockWin->addCurve(curve);
	}
	curve->addPoint(point.m_y.toFloat());
	m_main_plot->replot();
	qDebug() << "#><#: " << m_calc_time.elapsed();
}

void SerialCharX::on_x_axis_lock(void)
{
	m_main_plot->XscaleLock(!m_plotLockXButton->isChecked());
	m_main_plot->setAxisAutoScale(QwtPlot::xBottom, false);
}

void SerialCharX::on_y_axis_lock(void)
{
	m_main_plot->YscaleLock(!m_plotLockYButton->isChecked());
	m_main_plot->setAxisAutoScale(QwtPlot::xBottom, false);
}

void SerialCharX::on_plot_grid_sw(void)
{
	m_main_plot->gridOnOff(m_plotGridSw->isChecked());
}

void SerialCharX::on_recv_io_data(QByteArray data)
{
	m_calc_time.start();
	m_decoder->on_recv_data(data);
	qDebug() << "#><#: 1" << m_calc_time.elapsed();
	m_calc_time.start();
	m_consoleDockWin->log_data(data);
	qDebug() << "#><#: 2" << m_calc_time.elapsed();
}

void SerialCharX::createActions(void)
{
	// Files actions
	m_newAction = new QAction(tr("&New"), this);
	m_newAction->setIcon(QIcon(":/SerialCharX/Resources/images/new.png"));
	m_newAction->setShortcut(QKeySequence::New);
	m_newAction->setStatusTip(tr("Create a new plot"));
	connect(m_newAction, &QAction::triggered, this, &SerialCharX::newFile);

	m_openAction = new QAction(tr("&Open..."), this);
	m_openAction->setIcon(QIcon(":/SerialCharX/Resources/images/open.png"));
	m_openAction->setShortcut(QKeySequence::Open);
	m_openAction->setStatusTip(tr("Open an existing plot file"));
	connect(m_openAction, &QAction::triggered, this, &SerialCharX::openFile);

	m_saveAction = new QAction(tr("&Save"), this);
	m_saveAction->setIcon(QIcon(":/SerialCharX/Resources/images/save.png"));
	m_saveAction->setShortcut(QKeySequence::Save);
	m_saveAction->setStatusTip(tr("Save the plot to a file"));
	connect(m_saveAction, &QAction::triggered, this, &SerialCharX::save);

	m_saveAsAction = new QAction(tr("Save &As..."), this);
	m_saveAsAction->setStatusTip(tr("Save the spreadsheet under a new name"));
	connect(m_saveAsAction, &QAction::triggered, this, &SerialCharX::saveAs);

	m_exportAction = new QAction(tr("&Export"), this);
	m_exportAction->setIcon(QIcon(":/SerialCharX/Resources/images/export.ico"));
	m_exportAction->setStatusTip(tr("Export to ..."));
	connect(m_exportAction, &QAction::triggered, this, &SerialCharX::exportTo);
	
	m_printAction = new QAction(tr("&Print"), this);
	m_printAction->setIcon(QIcon(":/SerialCharX/Resources/images/printer.ico"));
	m_printAction->setStatusTip(tr("Print"));
	connect(m_printAction, &QAction::triggered, this, &SerialCharX::printTo);

	// Edit actions
	m_startAction = new QAction(tr("&Start"), this);
	m_startAction->setIcon(QIcon(":/SerialCharX/Resources/images/play.ico"));
	m_startAction->setShortcut(QKeySequence::New);
	m_startAction->setStatusTip(tr("Start plot from port data"));
	connect(m_startAction, &QAction::triggered, this, &SerialCharX::startPlot);

	m_stopAction = new QAction(tr("Sto&p"), this);
	m_stopAction->setIcon(QIcon(":/SerialCharX/Resources/images/pause.ico"));
	m_stopAction->setShortcut(QKeySequence::New);
	m_stopAction->setStatusTip(tr("Stop plot"));
	connect(m_stopAction, &QAction::triggered, this, &SerialCharX::stopPlot);

	m_plotSetupAction = new QAction(tr("Set&up"), this);
	m_plotSetupAction->setIcon(QIcon(":/SerialCharX/Resources/images/iosettup.ico"));
	m_plotSetupAction->setShortcut(QKeySequence::New);
	m_plotSetupAction->setStatusTip(tr("Plot settup"));
	connect(m_plotSetupAction, &QAction::triggered, this, &SerialCharX::plotSetup);

	
	m_plotCanvas = new QAction(tr("&Canvas"), this);
	m_plotCanvas->setIcon(QIcon(":/SerialCharX/Resources/images/canvas.ico"));
	m_plotCanvas->setShortcut(QKeySequence::Refresh);
	m_plotCanvas->setStatusTip(tr("Set plot canvas color"));
	connect(m_plotCanvas, &QAction::triggered, this, &SerialCharX::plotCanvasColorSet);

	m_plotAutoScaleAction = new QAction(tr("&AutoScale"), this);
	m_plotAutoScaleAction->setIcon(QIcon(":/SerialCharX/Resources/images/refresh.ico"));
	m_plotAutoScaleAction->setShortcut(QKeySequence::Refresh);
	m_plotAutoScaleAction->setStatusTip(tr("refresh plot, auto scale"));
	connect(m_plotAutoScaleAction, &QAction::triggered, this, &SerialCharX::plotAutoScale);

	m_plotDelAction = new QAction(tr("&Delete plot"), this);
	m_plotDelAction->setIcon(QIcon(":/SerialCharX/Resources/images/del.ico"));
	m_plotDelAction->setShortcut(QKeySequence::Delete);
	m_plotDelAction->setStatusTip(tr("Delete plot"));
	connect(m_plotDelAction, &QAction::triggered, this, &SerialCharX::plotDel);

	m_plotMaxAction = new QAction(tr("&Max plot"), this);
	m_plotMaxAction->setIcon(QIcon(":/SerialCharX/Resources/images/Maximize.ico"));
	m_plotMaxAction->setStatusTip(tr("Max plot"));
	connect(m_plotMaxAction, &QAction::triggered, this, &SerialCharX::plotMax);

	m_plotMinAction = new QAction(tr("&Min plot"), this);
	m_plotMinAction->setIcon(QIcon(":/SerialCharX/Resources/images/Minimize.ico"));
	m_plotMinAction->setStatusTip(tr("Min plot"));
	connect(m_plotMinAction, &QAction::triggered, this, &SerialCharX::plotMin);

	// view actions
	m_curveDockWinViewAction = new QAction(tr("&Curve List"), this);
	m_curveDockWinViewAction->setCheckable(true);
	connect(m_curveDockWinViewAction, &QAction::triggered, this, &SerialCharX::curveDockWinViewOnOff);
	connect(m_curveDockWinViewAction, &QAction::changed, this, &SerialCharX::curveDockWinViewOnOff);
	m_consoleDockWinViewAction = new QAction(tr("&Console"), this);
	m_consoleDockWinViewAction->setCheckable(true);
	connect(m_consoleDockWinViewAction, &QAction::triggered, this, &SerialCharX::consoleDockWinViewOnOff);
	connect(m_consoleDockWinViewAction, &QAction::changed, this, &SerialCharX::consoleDockWinViewOnOff);
}

void SerialCharX::createMenus(void)
{
	m_fileMenu = menuBar()->addMenu(tr("&File"));
	m_fileMenu->addAction(m_newAction);
	m_fileMenu->addAction(m_openAction);
	m_fileMenu->addAction(m_saveAction);
	m_fileMenu->addAction(m_saveAsAction);
	m_fileMenu->addAction(m_exportAction);
	m_fileMenu->addAction(m_printAction);

	m_editMenu = menuBar()->addMenu(tr("&Edit"));

	m_viewMenu = menuBar()->addMenu(tr("&View"));
	m_viewMenu->addAction(m_curveDockWinViewAction);
	m_viewMenu->addAction(m_consoleDockWinViewAction);
	
	m_optionMenu = menuBar()->addMenu(tr("&Option"));
	
	m_helpMenu = menuBar()->addMenu(tr("&Help"));
}

void SerialCharX::createToolBars(void)
{
	m_fileToolBar = addToolBar(tr("&File"));
	m_fileToolBar->setObjectName("FileToolBar");
	m_fileToolBar->addAction(m_newAction);
	m_fileToolBar->addAction(m_openAction);
	m_fileToolBar->addAction(m_saveAction);
	m_fileToolBar->addAction(m_exportAction);
	m_fileToolBar->addAction(m_printAction);
	
	m_ser_port_list = new comPortQComboBox(this);
	m_ser_bdrate_list = new QComboBox(this);
	m_ser_bdrate_list->addItem("115200");
	m_serPortToolBar = addToolBar(tr("&Serial"));
	m_serPortToolBar->setObjectName("SerialToolBar");
	m_serPortToolBar->addAction(m_startAction);
	m_serPortToolBar->addAction(m_stopAction);
	m_serPortToolBar->addAction(m_plotSetupAction);
	m_serPortToolBar->addWidget(m_ser_port_list);
	m_serPortToolBar->addWidget(m_ser_bdrate_list);

	m_plotLockXButton = new QPushButton(this);
	m_plotLockXButton->setCheckable(true);
	m_plotLockXButton->setMinimumSize(X_Y_LOCK_BT_SIZE, X_Y_LOCK_BT_SIZE);
	m_plotLockXButton->setMaximumSize(X_Y_LOCK_BT_SIZE, X_Y_LOCK_BT_SIZE);
	m_plotLockXButton->setIcon(QIcon(":/SerialCharX/Resources/images/x_arrowhead_right_lock.ico"));
	m_plotLockXButton->setStatusTip(tr("Lock x axis"));
	connect(m_plotLockXButton, &QPushButton::clicked, this, &SerialCharX::on_x_axis_lock);
	
	m_plotLockYButton = new QPushButton(this);
	m_plotLockYButton->setCheckable(true);
	m_plotLockYButton->setMinimumSize(X_Y_LOCK_BT_SIZE, X_Y_LOCK_BT_SIZE);
	m_plotLockYButton->setMaximumSize(X_Y_LOCK_BT_SIZE, X_Y_LOCK_BT_SIZE);
	m_plotLockYButton->setIcon(QIcon(":/SerialCharX/Resources/images/y_arrowhead_up_lock.ico"));
	m_plotLockYButton->setStatusTip(tr("Lock Y axis"));
	connect(m_plotLockYButton, &QPushButton::clicked, this, &SerialCharX::on_y_axis_lock);

	m_plotGridSw = new QPushButton(this);
	m_plotGridSw->setCheckable(true);
	m_plotGridSw->setMinimumSize(X_Y_LOCK_BT_SIZE, X_Y_LOCK_BT_SIZE);
	m_plotGridSw->setMaximumSize(X_Y_LOCK_BT_SIZE, X_Y_LOCK_BT_SIZE);
	m_plotGridSw->setIcon(QIcon(":/SerialCharX/Resources/images/gird.ico"));
	m_plotGridSw->setStatusTip(tr("Plot grid OnOff"));
	connect(m_plotGridSw, &QPushButton::clicked, this, &SerialCharX::on_plot_grid_sw);

	m_PlotToolBar = addToolBar(tr("&Plot"));
	m_PlotToolBar->setObjectName("PlotToolBar");
	m_PlotToolBar->addAction(m_plotCanvas);
	m_PlotToolBar->addAction(m_plotAutoScaleAction);
	m_PlotToolBar->addAction(m_plotDelAction);
	m_PlotToolBar->addAction(m_plotMaxAction);
	m_PlotToolBar->addAction(m_plotMinAction);
	m_PlotToolBar->addWidget(m_plotLockXButton);
	m_PlotToolBar->addWidget(m_plotLockYButton);
	m_PlotToolBar->addWidget(m_plotGridSw);
}

void SerialCharX::createDockWin(void)
{
	m_curveDockWin = new CurveitemDockWin(this, m_main_plot);
	addDockWidget(Qt::LeftDockWidgetArea, m_curveDockWin);

	m_consoleDockWin = new ConsoleDockWin(this);
	addDockWidget(Qt::BottomDockWidgetArea, m_consoleDockWin);
}

void SerialCharX::createMainPlotWin(void)
{
	m_main_plot = new Plot();
	setCentralWidget(m_main_plot);
}

void SerialCharX::closeEvent(QCloseEvent *event)
{
	if (m_ser)
	{
		m_ser->_close();
		delete m_ser;
	}
	if (m_curveDockWin)
	{
		delete m_curveDockWin;
	}
	if (m_main_plot)
	{
		delete m_main_plot;
	}
	writeSettings();
	QMainWindow::closeEvent(event);
}

void SerialCharX::writeSettings(void)
{
	qDebug() << "Save setting";
	QSettings settings;
	settings.setValue("windowState", saveState());
	settings.setValue("geometry", saveGeometry());
	settings.setValue("saveDir", m_curDir);
	settings.setValue("com", m_ser_port_list->currentIndex());
	settings.setValue("bdrate", m_ser_bdrate_list->currentIndex());
	settings.setValue("curveDockWinView", m_curveDockWinViewAction->isChecked());
	settings.setValue("consoleDockWinView", m_consoleDockWinViewAction->isChecked());

	// Console dock win
	settings.setValue("consoleDockWin", m_consoleDockWin->saveGeometry());
}

void SerialCharX::readSettings(void)
{
	qDebug() << "Read setting";
	QSettings settings;
	restoreState(settings.value("windowState").toByteArray());
	restoreGeometry(settings.value("geometry").toByteArray());
	m_curDir = settings.value("saveDir").toString();
	m_ser_port_list->setCurrentIndex(settings.value("com", 0).toInt());
	m_ser_bdrate_list->setCurrentIndex(settings.value("bdrate", 0).toInt());
	m_curveDockWinViewAction->setChecked(settings.value("curveDockWinView").toBool());
	m_consoleDockWinViewAction->setChecked(settings.value("consoleDockWinView").toBool());

	// Console dock win
	m_consoleDockWin->restoreGeometry(settings.value("consoleDockWin").toByteArray());
}
